package org.folio.rest.impl.other.notify.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.DynaBean;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import io.vertx.core.Context;
import io.vertx.core.Future;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.logging.Logger;
import io.vertx.core.logging.LoggerFactory;
import io.vertx.ext.mail.MailClient;
import io.vertx.ext.mail.MailConfig;
import io.vertx.ext.mail.MailMessage;
import io.vertx.ext.mail.StartTLSOptions;
import io.vertx.ext.web.client.HttpResponse;
import io.vertx.ext.web.client.WebClient;
import io.vertx.ext.web.client.WebClientOptions;
import org.folio.cql2pgjson.exception.FieldException;
import org.folio.rest.RestVerticle;
import org.folio.rest.impl.other.PartyUtil;
import org.folio.rest.impl.other.config.Config;
import org.folio.rest.impl.other.notify.INotify;
import org.folio.rest.jaxrs.model.NotifyLog;
import org.folio.rest.jaxrs.model.NotifyTemplate;
import org.folio.rest.persist.PgUtil;
import org.folio.rest.persist.cql.CQLWrapper;

import java.util.*;

public class INotifyImpl implements INotify {
    private static final Logger logger = LoggerFactory.getLogger("modparty");
    private String tenant;
    private String token;
    private String okapiUrl;
    private String reserveChannel;
    private WebClient webClient;
    private Map<String, String> okapiHeaders;
    private Context context;
    private String accountType = "1";
    private static final String OKAPI_HEADER_URL = "x-okapi-url";
    private  NotifyLog notifyLog;

    private Config config;

    public INotifyImpl(Map<String, String> okapiHeaders,
                       Context vertxContext, String accountType, String reserveChannel) {

        this.webClient = WebClient.create(vertxContext.owner());
        this.context = vertxContext;
        this.accountType = accountType;
        this.reserveChannel = reserveChannel;
        this.tenant = okapiHeaders.get(RestVerticle.OKAPI_HEADER_TENANT);
        this.token = okapiHeaders.get(RestVerticle.OKAPI_HEADER_TOKEN);
        this.okapiUrl = okapiHeaders.get(OKAPI_HEADER_URL);
        this.okapiHeaders = okapiHeaders;
        this.config = new Config(vertxContext.owner());
    }


    private void bySMS(String mobile, String content) {
        WebClientOptions options = new WebClientOptions()
                .setUserAgent("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36");
        options.setKeepAlive(false);
        WebClient web = WebClient.create(context.owner(),options);
        NotifyLog saveObject = new NotifyLog();
        BeanUtil.copyProperties(this.notifyLog,saveObject);
        saveObject.setSendDate(DateUtil.formatDateTime(new Date()));
        saveObject.setMessage(content);
        saveObject.setNotifyMode("2");

        this.config.getAll().setHandler(re->{
           if (re.succeeded()){
               Map<String, Object> map = re.result();
               String smsUri = map.get("smsUri").toString();
               map.put("phone",mobile);
               map.put("content",content);
               String urlParam = StrUtil.format( smsUri, map);

               web.get((Integer) map.get("smsPoint"),map.get("smsNotifyIp").toString(),urlParam).send(reply->{
                   if (reply.succeeded()){
                       HttpResponse<Buffer> response = reply.result();
                       if ("200".equals(""+response.statusCode())){
                           PgUtil.postgresClient(this.context,this.okapiHeaders).save("notify_log",saveObject,saveReply->{
                               if (saveReply.succeeded())
                               {
                                   logger.info(" sms notify save success .");
                               }
                           });
                       }
                   }
               });
           }
        });

    }

    public Future<Object> sendSms(String reserveId, String mobile, String content) {
        Future<Object> future = Future.future();
        WebClientOptions options = new WebClientOptions()
                .setUserAgent("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36");
        options.setKeepAlive(false);
        WebClient web = WebClient.create(context.owner(), options);
        NotifyLog saveObject = new NotifyLog();
        saveObject.setSendDate(DateUtil.formatDateTime(new Date()));
        saveObject.setMessage(content);
        saveObject.setNotifyMode("2");
        saveObject.setId(reserveId);
        this.config.getAll().setHandler(re -> {
            if (re.succeeded()) {
                Map<String, Object> map = re.result();
                String smsUri = map.get("smsUri").toString();
                map.put("phone", mobile);
                map.put("content", content);
                String urlParam = StrUtil.format(smsUri, map);

                web.get((Integer) map.get("smsPoint"), map.get("smsNotifyIp").toString(), urlParam).send(reply -> {
                    if (reply.succeeded()) {
                        HttpResponse<Buffer> response = reply.result();
                        if ("200".equals(""+response.statusCode())){
                            saveObject.setSendStatus(true);
                            future.complete(saveObject);

                        }else{
                            saveObject.setSendStatus(false);
                            future.complete(saveObject);
                        }
                    }else{
                        saveObject.setSendStatus(false);
                        future.complete(saveObject);
                    }
                });
            }
        });
        return future;
    }

    private void byEmail(String email, String content) {
        this.config.getAll().setHandler(re->{
            Map<String, Object> map = re.result();

            MailConfig config = new MailConfig();
            config.setHostname(map.get("hostName").toString());
            config.setSsl(true);
            config.setPort(465);
            config.setStarttls(StartTLSOptions.REQUIRED);
            config.setUsername(map.get("emailNotifyAdmin").toString());
            config.setPassword(map.get("emailNotifyPass").toString());
            MailClient mailClient = MailClient.createShared(this.context.owner(), config);

            MailMessage message = new MailMessage();
            message.setFrom(map.get("emailSendFrom").toString());
            message.setTo(map.get("emailSendTo").toString());
            message.setCc(email);

            message.setSubject(map.get("emailSendSubject").toString());
            message.setText(content);
            NotifyLog saveObject = new NotifyLog();
            BeanUtil.copyProperties(this.notifyLog,saveObject);
            saveObject.setSendDate(DateUtil.formatDateTime(new Date()));
            saveObject.setMessage(content);
            saveObject.setNotifyMode("3");
            mailClient.sendMail(message, result -> {
                if (result.failed()){
                    result.cause().printStackTrace();
                    logger.info(result.cause().getMessage());
                    return;
                }
                PgUtil.postgresClient(this.context,this.okapiHeaders).save("notify_log",saveObject,saveReply->{
                    if (saveReply.succeeded())
                    {
                        logger.info(" email notify save success .");
                    }
                });
            });
        });



    }


    private void byWeChat(String openId, String content) {

    }


    @Override
    public void notifyCenter(Object object, Integer notifyType) throws FieldException {
        DynaBean bean = DynaBean.create(object);
        Map<String, Object> map = new HashMap<>();
        String otherMessage = "";
        Object value = bean.invoke("getPartyName");
        map.put("activityName", value);

        map.put("activityStartTime", bean.invoke("getPartyStartDate"));
        map.put("activityEndTime", bean.invoke("getPartyEndDate"));
        Object list = bean.safeGet("readerReserveGroup");
        if (list != null && "ArrayList".equals(list.getClass().getSimpleName())) {
            List<Object> list1 = (List<Object>) list;
            Object user = list1.get(0);
            map.putAll(BeanUtil.beanToMap(user));
        }
        if (notifyType.equals(Integer.valueOf(4))){
            Object remark = bean.invoke("getRemark");
            if (remark !=null){
                otherMessage ="拒绝理由："+ remark.toString();
            }
        }
        NotifyLog notifyLog = new NotifyLog();
        notifyLog.setAccountType(accountType);
        notifyLog.setId(UUID.randomUUID().toString());
        notifyLog.setName(map.get("name").toString());
        notifyLog.setPhoneNumber(map.get("mobilePhone").toString());
        notifyLog.setUserAccount(""+map.get("barcode"));
        notifyLog.setPartyName(map.get("activityName").toString());
        notifyLog.setReserveChannel(this.reserveChannel);
        notifyLog.setMessageType(notifyType.toString());
        this.notifyLog = notifyLog;
        CQLWrapper cql = PartyUtil.getCQL("(type = " + notifyType + "*)", 100, 0, "notify_template");
        String finalOtherMessage = otherMessage;
        PgUtil.postgresClient(this.context, this.okapiHeaders)
                .get("notify_template", NotifyTemplate.class, new String[]{"*"}, cql,
                        true, false, reply -> {
                            if (reply.succeeded()) {
                                List<NotifyTemplate> notifyTemplateList = reply.result().getResults();
                                notifyTemplateList.forEach(a -> {
                                    Integer channel = a.getNotice();
                                    // 1 WeChat 2 sms 3 email
                                    switch (channel) {
                                        case 1:
                                            // this.byWeChat();
                                            break;
                                        case 2:
                                            if (!StrUtil.isBlankOrUndefined(a.getTemplate()) && map.get("mobilePhone") != null) {
                                                String content = StrUtil.format(a.getTemplate(), map);

                                                this.bySMS(map.get("mobilePhone").toString(), content+ finalOtherMessage);
                                            }

                                            break;
                                        case 3:
                                            if (!StrUtil.isBlankOrUndefined(a.getTemplate()) && map.get("email") != null) {
                                                String content = StrUtil.format(a.getTemplate(), map);

                                                this.byEmail(map.get("email").toString(), content+ finalOtherMessage);
                                            }
                                            break;
                                        default:
                                            logger.info(" notify err . notify channel is null");
                                            break;
                                    }
                                });
                            }
                        });

    }


}
